const privateWeakMap = new WeakMap()
function getConcurrent(_this: object) {
  return privateWeakMap.get(_this)
}
class ConcurrentInterceptors {
  /**
   * 最大并发数量
   * @param maxProgressCount
   * @typeof number | null
   */
  constructor(maxProgressCount: number | null) {
    privateWeakMap.set(this, {
      // 最大并发数量
      _maxProgressCount: maxProgressCount,
      // 进行中的任务数量
      _inProgressCount: 0,
      // 等待中的任务
      _waitingArr: []
    })
  }

  /**
   * 拦截器
   * @return Promise.resolve()
   */
  interceptors = () => {
    const { _inProgressCount, _maxProgressCount } = getConcurrent(this)
    return new Promise<void>(resolve => {
      // 非数字、isNaN、不大于0 不拦截
      if (typeof _maxProgressCount !== 'number' || isNaN(_maxProgressCount) || _maxProgressCount <= 0) {
        resolve()
        return
      }
      // 当前进行的任务数量是否大于最大并发数量
      if (_inProgressCount < _maxProgressCount) {
        // 未超出最大并发数量
        getConcurrent(this)._inProgressCount += 1
        resolve()
      } else {
        // 超出最大并发数量
        getConcurrent(this)._waitingArr.push(resolve)
      }
    })
  }

  /**
   * 启动下一个被拦截的任务
   */
  next = () => {
    // 当前进行中的数量减一
    getConcurrent(this)._inProgressCount -= 1

    // 等待发送的请求的移除一个
    const nextResolve = getConcurrent(this)._waitingArr.shift()
    if (nextResolve) {
      // 要进行下一个任务了 当前进行中的数量加一
      getConcurrent(this)._inProgressCount += 1
      nextResolve()
    }
  }

  /**
   * 更新最大并发数量
   * @param newMaxProgressCount
   */
  updateMaxProgressCount = (newMaxProgressCount: number | null) => {
    getConcurrent(this)._maxProgressCount = newMaxProgressCount
  }

  /**
   * 获取_maxProgressCount属性值
   */
  get maxProgressCount() {
    return getConcurrent(this)._maxProgressCount
  }
  set maxProgressCount(newVal) {
    this.updateMaxProgressCount(newVal)
  }

  /**
   * 获取_sendAxiosIngCount属性值
   */
  get inProgressCount() {
    return getConcurrent(this)._inProgressCount
  }
  set inProgressCount(newVal) {
    throw new Error(`inProgressCount为只读属性`)
  }

  /**
   * 获取_awaitSendAxiosArr属性值
   */
  get waitingArr() {
    return getConcurrent(this)._waitingArr
  }
  set waitingArr(newVal) {
    throw new Error(`waitingArr为只读属性`)
  }
}

export default ConcurrentInterceptors
